/*****************************************************************************
 *   Copyright 2011 ZHUANG Yuan              	                             *
 *   SudokuITS as Final Year Project for BScCS, City University of Hong Kong *
 *                                      									 *
 *   Licensed under the Apache License, Version 2.0 (the "License");         *
 *   you may not use this file except in compliance with the License.        *
 *   You may obtain a copy of the License at                                 *
 *                                                                           *
 *   http://www.apache.org/licenses/LICENSE-2.0                              *
 *                                                                           *
 *   Unless required by applicable law or agreed to in writing, software     *
 *   distributed under the License is distributed on an "AS IS" BASIS,       *
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.*
 *   See the License for the specific language governing permissions and     *
 *   limitations under the License.                                          *
 *****************************************************************************/

package android.sudoku.its.tutor;

import java.util.HashMap;
import java.util.List;

import android.content.Context;
import android.sudoku.its.expert.Expert;
import android.sudoku.its.util.GameVariables;
import android.sudoku.its.views.GamePage;
import android.sudoku.its.views.R;
import android.util.Log;

/**
 * Generate instruction
 * @author 51158282
 *
 */
public class InstructionGenerator {
	private StrategyExplainer strategyExplainer;
	private TutorUtil tutorUtil;
	
	// A hash map that maps strategy indexes with strategy names
	private HashMap<Integer, String> strategyMap;
	
	// Instructions
	private String ASSIGN_TO = "";
	private String CELL_BEGIN = "";
	private String NOT = "";
	private String A_VALID_VALUE_FOR = "";
	private String TO = "";
	private String CELL_END = "";
	
	// Instruction language set by the user, default English
	private String langPref = GameVariables.LANG_ENGLISH;
	
	public InstructionGenerator(Context context, String langPref) {
		strategyExplainer = new StrategyExplainer();
		tutorUtil = new TutorUtil();
		
		// Initialize strategy map that maps strategy indexes with strategy names 
		String[] strategyIndexesStr = context.getResources().getStringArray(R.array.strategy_indexes);
        String[] strategyNames = context.getResources().getStringArray(R.array.strategies); 		
		int[] strategyIndexes = {0, 0, 0, 0, 0, 0};
		
        for (int i = 0; i < strategyIndexesStr.length; i++)
        	strategyIndexes[i] = Integer.parseInt(strategyIndexesStr[i]);
		strategyMap = new HashMap<Integer, String>();
        for (int i = 0; i < strategyIndexes.length; i++) 
        	strategyMap.put(strategyIndexes[i], strategyNames[i]);
        
        // Initialize instruction language to be default English
        this.langPref = langPref;
        
        // Initialize instruction wordings
        loadInstructions(context);        
	}
	
	private void loadInstructions(Context context) {		
		CELL_END = context.getResources().getString(R.string.cell_end);	
		if (langPref.equals(GameVariables.LANG_CHINESE)) { // language preference is Chinese
			ASSIGN_TO = context.getResources().getString(R.string.assign_to_cn);
			CELL_BEGIN = context.getResources().getString(R.string.cell_begin_cn);
			NOT = context.getResources().getString(R.string.not_cn);
			TO = context.getResources().getString(R.string.to_cn);	
				
		}
		else {	// language preference is English
			ASSIGN_TO = context.getResources().getString(R.string.assign_to_en);
			CELL_BEGIN = context.getResources().getString(R.string.cell_begin_en);
			NOT = context.getResources().getString(R.string.not_en);
			A_VALID_VALUE_FOR = context.getResources().getString(R.string.a_valid_value_for_en);
		}
	}
	
	/**
	 * Give brief instruction to advanced level student
	 * @param index		Index of the strategy name in the index-name hash map 
	 * @return			Instruction to be output
	 */
	protected String giveHighLevelInstr(int strategyIndex, int nRow, int nCol) {				
		return "\n\nLook at " + CELL_BEGIN + tutorUtil.getRowString(nRow) + ", " + tutorUtil.getColumnString(nCol) + CELL_END + 
				" and its related houses. " + "There is a strategy that can apply to it. \n Can you try to find that strategy?";		
	}
	
	protected String giveMiddleLevelInstr(int strategyIndex, int nRow, int nCol) {
		return "\n\nLook at " + CELL_BEGIN + tutorUtil.getRowString(nRow) + ", " + tutorUtil.getColumnString(nCol) + CELL_END + 
				" and its related houses. " + "Can you see " + strategyMap.get(strategyIndex) + "?";
	}
	
	protected String giveLowLevelInstr(Context context, int strategyIndex, int nRow, int nCol, int[][] clues) {
		String strategyExplanation = "";
		Expert expert = ((GamePage) context).getExpert();		
		List<List<Integer>> cm = expert.getCandidateMatrix();
		
		switch(strategyIndex) {
			case GameVariables.FULL_HOUSE_INDEX:
				strategyExplanation = strategyExplainer.explainFullHouse(nRow, nCol, clues);
				break;		
			case GameVariables.NAKED_SINGLE_INDEX:
				strategyExplanation = strategyExplainer.explainNakedSingle(nRow, nCol);
				break;
			case GameVariables.HIDDEN_SINGLE_INDEX:
				strategyExplanation = strategyExplainer.explainHiddenSingle(nRow, nCol, cm);
				break;
			case GameVariables.NAKED_PAIR_INDEX:
				strategyExplanation = strategyExplainer.explainNakedPair(nRow, nCol, cm);
				break;
			case GameVariables.HIDDEN_PAIR_INDEX:
				strategyExplanation = strategyExplainer.explainHiddenPair(nRow, nCol, cm); 
				break;
			case GameVariables.LOCKED_CANDIDATE_INDEX:
				break;
		}
		
		return "\n\nLook at " + CELL_BEGIN + tutorUtil.getRowString(nRow) + ", " + tutorUtil.getColumnString(nCol) + CELL_END + 
				" and its related houses. " + strategyExplanation;
	}
	
	protected String giveAnswer(Context context, int strategyIndex, int nRow, int nCol, int[][] clues, Tutor tutor) {
		String msg = "";
		int cellIndex = nRow * GameVariables.HOUSE_SIZE + nCol;	
		Expert expert = ((GamePage) context).getExpert();
		List<List<Integer>> cm = expert.getCandidateMatrix();
		
		switch (strategyIndex) {
			case GameVariables.FULL_HOUSE_INDEX:
			case GameVariables.NAKED_SINGLE_INDEX:
				int answer = cm.get(cellIndex).get(0);
				msg = "\n\nThe correct value for" + CELL_BEGIN + tutorUtil.getRowString(nRow) + ", " + tutorUtil.getColumnString(nCol) + CELL_END + 
				" is " + Integer.toString(answer) + ".";
				if ((nRow == 9) && (nCol == 5))
					Log.d("", "prepare to debug");
				((GamePage) context).handleAutoFillAnswer(nRow, nCol, answer);
				break;
			case GameVariables.HIDDEN_SINGLE_INDEX:
				msg = "\n\n" + strategyExplainer.giveHiddenSingleResult(context, nRow, nCol, cm);
				break;
			case GameVariables.NAKED_PAIR_INDEX:
				msg = "\n\n" + strategyExplainer.giveNakedPairResult(expert, nRow, nCol, cm, clues, tutor);
				break;
			case GameVariables.HIDDEN_PAIR_INDEX:
				msg = "\n\n" +  strategyExplainer.giveHiddenPairResult(expert, nRow, nCol, cm, clues, tutor);
				break;
			case GameVariables.LOCKED_CANDIDATE_INDEX:
				break;
		}
					
		return msg;
	}
	
	/**
	 * Give instruction for valid number assignment
	 * @param num			Number input by user
	 * @param nRow			Row index of the cell received user input
	 * @param nCol			Column index of the cell received user input
	 * @return				A string containing instructions to be given to the user
	 */	
	protected String giveInstrForValidAsg(int num, int nRow, int nCol) {
		String instrMsg = "";
		
		// Set instruction
		if (langPref.equals(GameVariables.LANG_ENGLISH)) {	// English instructions
			instrMsg = "\n\n" + "You are correct! " + Integer.toString(num) + ASSIGN_TO + CELL_BEGIN + 
					Integer.toString(nRow + 1) + ", " + 
					Character.toString((char) (nCol + 'A')) + CELL_END + ".";
		}
		else {	// Chinese instructions
			instrMsg = "\n\n" + ASSIGN_TO + Integer.toString(num) + TO + CELL_BEGIN + 
					Integer.toString(nRow + 1) + ", " + 
					Character.toString((char) (nCol + 'A')) + CELL_END;
		}
		
		return instrMsg;
	}
	
	/**
	 * Give instruction for invalid number assignment
	 * @param langPref		Instruction language preference
	 * @param num			Number input by user
	 * @param nRow			Row index of the cell received user input
	 * @param nCol			Column index of the cell received user input
	 * @return				A string containing instructions to be given to the user
	 */
	protected String giveInstrForInvalidAsg(int num, int nRow, int nCol) {
		String instrMsg = "";
		
		// Set instruction
		if (langPref.equals(GameVariables.LANG_ENGLISH)) {	// English instructions
			instrMsg = "\n\n" + "Can you try again? " + Integer.toString(num) + NOT + A_VALID_VALUE_FOR + CELL_BEGIN + 
					Integer.toString(nRow + 1) + ", " + 
					Character.toString((char) (nCol + 'A')) + CELL_END + ".";						
		}
		else {	// Chinese instructions
			instrMsg = "\n\n" + Integer.toString(num) + NOT + ASSIGN_TO + TO + CELL_BEGIN + 
					Integer.toString(nRow + 1) + ", " + 
					Character.toString((char) (nCol + 'A')) + CELL_END;							
		}
		
		return instrMsg;
	}
}
